package com.cs.game.core;

import com.cs.game.core.constant.Constants;
import com.cs.game.core.utils.ScoreFileUtil;
import com.cs.game.core.view.imageview.*;
import com.cs.game.core.view.pane.MyStage;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;

/**
 * Game entry class, main function is to initialize the game window artboard, initialize the score from the file, initialize the entry interface, etc.
 */
public class Main extends Application {
    private AnimationTimer timer;
    private MyStage background;
    private Animal animal;
    private int highestScore = 0;

    public static void main(String[] args) {
        launch(args);
    }

    /**
     * Entry method for game running
     * Initialize the scene and start the game
     * @param primaryStage
     * @throws Exception
     */
    @Override
    public void start(Stage primaryStage) throws Exception {
        background = new MyStage();
        initHighestScoreFromFile();
        initBackgroudPane();
        initHomePage();
        Scene scene = new Scene(background, 600, 800);
        background.start();
        primaryStage.setScene(scene);
        primaryStage.show();
        background.playMusic();
        createTimer();
        timer.start();
    }

    /**
     * Create an AnimationTimer to dynamically update the scoreboard and determine if the game fails or stops
     * When winning the game, write the highest score to the file and display a popup
     * When the game fails, determine whether it is the highest score, if yes, write the result to a file, pop the box and display the current score and the highest historical score
     */
    public void createTimer() {
        timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                if (animal.changeScore()) {
                    setNumber(animal.getPoints());
                }
                if (animal.getStop()) {
                    System.out.print("STOPP:");
                    background.stopMusic();
                    stop();
                    background.stop();
                    if (animal.getPoints() > highestScore) {
                        highestScore = animal.getPoints();
                    }
                    writeHighestScoreToFile();
                    Alert alert = new Alert(AlertType.INFORMATION);
                    alert.setTitle("You Have Won The Game!");
                    alert.setHeaderText("Your High Score: " + animal.getPoints() + "!");
                    alert.setContentText("Highest Score: " + highestScore);
                    alert.show();
                }
                if (animal.isFailed()) {
                    stop();
                    if (animal.getPoints() > highestScore) {
                        highestScore = animal.getPoints();
                        writeHighestScoreToFile();
                    }
                    Alert alert = new Alert(AlertType.INFORMATION);
                    alert.setTitle("You Are Failed!");
                    alert.setHeaderText("Current Score: " + animal.getPoints() + "!");
                    alert.setContentText("Your Highest Score: " + highestScore);
                    alert.setOnCloseRequest(h-> {
                        animal.setFailed(false);
                        start();
                    });
                    alert.show();
                }
            }
        };
    }

    @Override
    public void stop() {
        timer.stop();
    }

    public void setNumber(int n) {
        int shift = 0;
        while (n > 0) {
            int d = n / 10;
            int k = n - d * 10;
            n = d;
            background.add(new Digit(k, 30, 360 - shift, 25));
            shift += 30;
        }
    }


    /**
     * Read and initialize historical highest score from file
     */
    private void initHighestScoreFromFile() {
        String path = Main.class.getClassLoader().getResource(Constants.FILE_SCOER_PATH).getPath();
        List<String> list = ScoreFileUtil.readFileByLine(path);
        if (CollectionUtils.isNotEmpty(list)) {
            this.highestScore = Integer.parseInt(list.get(0));
        } else {
            this.highestScore = 0;
        }
    }

    private void writeHighestScoreToFile() {
        ScoreFileUtil.writeLineToFile(String.valueOf(highestScore));
    }

    private void initBackgroudPane() {
        initBackground();
        initLog();
        initTurtle();
        initEnd();
        initAnimal();
    }

    /**
     * Initialize Background
     */
    private void initBackground() {
        ClassLoader classLoader = this.getClass().getClassLoader();
        String backgroundImg = classLoader.getResource(Constants.IMAGE_BACKGROUND2_PATH).toString();
        BackgroundImage froggerback = new BackgroundImage(backgroundImg);
        background.add(froggerback);
    }

    /**
     * Initialize Log
     */
    private void initLog() {
        ClassLoader classLoader = this.getClass().getClassLoader();
        String imgLog3 = classLoader.getResource(Constants.IMAGE_LOG3_PATH).toString();
        String imgLogs = classLoader.getResource(Constants.IMAGE_LOGS_PATH).toString();
        background.add(new Log(imgLog3, 150, 0, 166, 0.75));
        background.add(new Log(imgLog3, 150, 220, 166, 0.75));
        background.add(new Log(imgLog3, 150, 440, 166, 0.75));
        background.add(new Log(imgLogs, 300, 0, 276, -2));
        background.add(new Log(imgLogs, 300, 400, 276, -2));
        background.add(new Log(imgLog3, 150, 50, 329, 0.75));
        background.add(new Log(imgLog3, 150, 270, 329, 0.75));
        background.add(new Log(imgLog3, 150, 490, 329, 0.75));
    }

    /**
     * Initialize Turtle
     */
    private void initTurtle() {
        background.add(new Turtle(500, 376, -1, 130, 130));
        background.add(new Turtle(300, 376, -1, 130, 130));
        background.add(new WetTurtle(700, 376, -1, 130, 130));
        background.add(new WetTurtle(600, 217, -1, 130, 130));
        background.add(new WetTurtle(400, 217, -1, 130, 130));
        background.add(new WetTurtle(200, 217, -1, 130, 130));
    }

    /**
     * Initialize End
     */
    private void initEnd() {
        background.add(new End(13, 96));
        background.add(new End(141, 96));
        background.add(new End(141 + 141 - 13, 96));
        background.add(new End(141 + 141 - 13 + 141 - 13 + 1, 96));
        background.add(new End(141 + 141 - 13 + 141 - 13 + 141 - 13 + 3, 96));
    }

    /**
     * Initialize Animal
     */
    private void initAnimal() {
        ClassLoader classLoader = getClass().getClassLoader();
        String imgFroggerUp = classLoader.getResource(Constants.IMAGE_FROGGERUP_PATH).toString();
        String imgTruck1Right = classLoader.getResource(Constants.IMAGE_TRUCK1RIGHT_PATH).toString();
        String imgTruck2Right = classLoader.getResource(Constants.IMAGE_TRUCK2RIGHT_PATH).toString();
        String imgCar1Left = classLoader.getResource(Constants.IMAGE_CAR1LEFT_PATH).toString();
        animal = new Animal(imgFroggerUp);
        background.add(animal);
        background.add(new Obstacle(imgTruck1Right, 0, 649, 1, 120, 120));
        background.add(new Obstacle(imgTruck1Right, 300, 649, 1, 120, 120));
        background.add(new Obstacle(imgTruck1Right, 600, 649, 1, 120, 120));
        background.add(new Obstacle(imgCar1Left, 100, 597, -1, 50, 50));
        background.add(new Obstacle(imgCar1Left, 250, 597, -1, 50, 50));
        background.add(new Obstacle(imgCar1Left, 400, 597, -1, 50, 50));
        background.add(new Obstacle(imgCar1Left, 550, 597, -1, 50, 50));
        background.add(new Obstacle(imgTruck2Right, 0, 540, 1, 200, 200));
        background.add(new Obstacle(imgTruck2Right, 500, 540, 1, 200, 200));
        background.add(new Obstacle(imgCar1Left, 500, 490, -5, 50, 50));
        background.add(new Digit(0, 30, 360, 25));
    }

    /**
     * Initialize the homepage. When you first enter the game, the homepage will be displayed. Click the game introduction button to pop up the game introduction information.
     * Click the game start button to start the game
     */
    private void initHomePage() {
        HomePage homePage = new HomePage(getClass().getClassLoader().getResource(Constants.IMAGE_BACKGROUND1_PATH).toString());
        Button startGameBt = new Button(Constants.TEXT_START_GAME);
        Button gameIntroduction = new Button(Constants.TEXT_GAME_INTRODUCTION);
        startGameBt.setLayoutX(100);
        startGameBt.setLayoutY(400);
        gameIntroduction.setLayoutX(300);
        gameIntroduction.setLayoutY(400);
        startGameBt.setOnMouseClicked(h -> {
            startGameBt.setVisible(false);
            gameIntroduction.setVisible(false);
            homePage.setVisible(false);
            animal.setCanMove(true);
        });
        gameIntroduction.setOnMouseClicked(h -> {
            Alert alert = new Alert(AlertType.INFORMATION);
            alert.setTitle(Constants.TEXT_GAME_INTRODUCTION);
            alert.setHeaderText(Constants.TEXT_OPERATION_MANUAL);
            alert.setContentText(Constants.GAME_INTRODUCTION);
            alert.show();
        });
        background.add(homePage);
        background.addButton(startGameBt);
        background.addButton(gameIntroduction);
    }
}
